{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://hilpisch.com/tpq_logo.png\" alt=\"The Python Quants\" width=\"35%\" align=\"right\" border=\"0\"><br><br><br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Listed Volatility and Variance Derivatives\n",
    "\n",
    "**Wiley Finance (2017)**\n",
    "\n",
    "Dr. Yves J. Hilpisch | The Python Quants GmbH\n",
    "\n",
    "http://tpq.io | [@dyjh](http://twitter.com/dyjh) | http://books.tpq.io\n",
    "\n",
    "<img src=\"http://hilpisch.com/../images/lvvd_cover.png\" alt=\"Derivatives Analytics with Python\" width=\"30%\" align=\"left\" border=\"0\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# VSTOXX Index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This chapter is about the (re-) calculation of the VSTOXX index, the volatility index based on EURO STOXX 50 index options. The goal is to achieve a good understanding of the processes and underlying mechanics of calculating the VSTOXX index. You will find all background information as well as Python code that will enable you to recalculate historical VSTOXX index values as well as current ones in (almost) real-time. The chapter about the _Model-Free Replication of Variance_ provides the theoretical background for the concepts presented in this chapter."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The (main) VSTOXX index itself is based on two sub-indexes, which themselves are derived from Eurex option series for both European puts and calls on the EURO STOXX 50 index. The algorithm, and therefore this chapter as well, is comprised of three main parts:\n",
    "\n",
    "* collect and clean-up the data of the necessary option series\n",
    "* compute the sub-indexes from the option data\n",
    "* compute the VSTOXX index from the relevant sub-indexes\n",
    "\n",
    "A few remarks about the option series and sub-indexes used and their expiry dates and time horizons, respectively, seem in order. There are eight sub-indexes of the VSTOXX which each measure the implied volatility of an option series with fixed expiry. For example, the VSTOXX 1M sub-index starts with the option series that has one month expiry and is calculated up to two days prior to the fixed maturity date of the according option series. The VSTOXX index measures the implied volatility of an \"imaginary\" options series with a fixed time to expiry of 30 days. This is achieved through linear interpolation of the two nearest sub-indexes, generally VSTOXX 1M and VSTOXX 2M. On the two days before VSTOXX 1M expiry, the VSTOXX 2M and VSTOXX 3M are used instead and an extrapolation takes place."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following table lists all the sub-indexes and provides additional information."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    ============ ======= ============== ===========================================\n",
    "     Sub-index    Code    ISIN           Settlement date of the option series used\n",
    "    ============ ======= ============== ===========================================\n",
    "     VSTOXX 1M    V6I1    DE000A0G87B2   The last available within 1 month\n",
    "     VSTOXX 2M    V6I2    DE000A0G87C0   The last available within 2 months\n",
    "     VSTOXX 3M    V6I3    DE000A0G87D8   The last available within 3 months\n",
    "     VSTOXX 6M    V6I4    DE000A0G87E6   The last available within 6 months\n",
    "     VSTOXX 9M    V6I5    DE000A0G87F3   The last available within 9 months\n",
    "     VSTOXX 12M   V6I6    DE000A0G87G1   The last available within 12 months\n",
    "     VSTOXX 18M   V6I7    DE000A0G87H9   The last available within 18 months\n",
    "     VSTOXX 24M   V6I8    DE000A0G87J5   The last available within 24 months\n",
    "    ============ ======= ============== ==========================================="
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Collecting Option Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As pointed out, the VSTOXX is based on two sub-indexes, generally the VSTOXX 1M and VSTOXX 2M, sometimes VSTOXX 2M and VSTOXX 3M. The sub-indexes themselves are based on the option series on the EURO STOXX 50 index with respective time to expiry. We therefore need the prices of all options with maturities up to 3 months. We use historical data as provided by Eurex itself as the data source. See the web site http://bit.ly/1GY5KCI."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The code to collect the data can be found in the module ``index_collect_option_data.py`` (see appendix for the complete script). Like usual, the module starts with some imports and parameter definitions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!sed -n 11,24p scripts/index_collect_option_data.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition, the module contains six functions. The first is ``collect_option_series()``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys; sys.path.append('./scripts/')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import index_collect_option_data as icod"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.collect_option_series??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function collects the data of the option series with maturity in the month ``month`` and year ``year``. It is called by the ``function start_collecting()`` and calls the ``function get_data()`` for every single day from the date ``start`` to today. It returns a complete set of prices (both puts and calls) for that series.\n",
    "\n",
    "The second function is ``get_data()``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.get_data??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This one is called by the function ``collect_option_series()`` and calls itself the functions ``get_data_from_www()``, ``parse_data(data, date)`` and ``merge_and_filter()``. It returns the prices of the option series with expiry date in month ``month`` and year ``year`` for the day ``date``.\n",
    "\n",
    "The third function is ``get_data_from_www()``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.get_data_from_www??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function collects the prices of an option series for a single day (defined by ``date``) from the web. The option series is defined by the date of its expiry, given by ``matMonth`` and ``matYear``, the type of the options is given by ``oType`` which can be either ``Put`` or ``Call``. It returns a complete HTML file.\n",
    "\n",
    "``merge_and_filter()`` is the fourth function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.merge_and_filter??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This one gets two time series ``puts`` and ``calls`` (typically of the same option series), merges them, filters out all options with prices below 0.5 and returns the resulting pandas ``DataFrame`` object.\n",
    "\n",
    "``parse_data()`` is the fifth function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.parse_data??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It gets the string ``data`` which contains the HTML text delivered by function ``get_data_from_www()``, parses that string to a pandas ``DataFrame`` object with double index ``date`` and ``strike price`` and returns that object.\n",
    "\n",
    "The sixth and final function is ``data_collection()``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "icod.data_collection??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function is to initiate and finalize the collection of all relevant option series data sets. It saves the resulting data in a file named ``index_option_series.h5``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "path = './data/'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us collect option data since all other steps depend on this data. We import the module as ``icod``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import datetime as dt\n",
    "import warnings; warnings.simplefilter('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, fix a target day relative to today such that you hit a business day for which closing data is available."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "today = dt.datetime.now()\n",
    "## make sure to hit a business day\n",
    "target_day = today - dt.timedelta(days=2)\n",
    "ds = target_day.strftime('%Y%m%d')\n",
    "ds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "URL = 'https://www.eurex.com/ex-en/data/statistics/market-statistics-online/'\n",
    "URL += '100!onlineStats?productGroupId=13370&productId=69660&viewType=3&'\n",
    "URL += 'cp=%s&month=%s&year=%s&busDate=%s'\n",
    "URL % ('Call', 12, 2020, '20201111')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, for example, collect option data for puts and calls with a maturity as defined by the parameters as follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## adjust maturity parameters if necessary\n",
    "call_data = icod.get_data_from_www(oType='Call', matMonth=12,\n",
    "                                   matYear=2020, date=ds)\n",
    "put_data = icod.get_data_from_www(oType='Put', matMonth=12,\n",
    "                                  matYear=2020, date=ds)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The return objects need to be parsed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## parse the raw data\n",
    "calls = icod.parse_data(call_data, target_day)\n",
    "puts = icod.parse_data(put_data, target_day)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us have a look at some meta information about the call options data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "calls.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calls.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And about the put options data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "puts.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In a next step, we take out the daily settlement prices for both the puts and calls and define two new ``DataFrame`` objects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "calls = pd.DataFrame(calls.rename(\n",
    "        columns={'Daily settlem. price': 'Call_Price'}\n",
    "                            ).pop('Call_Price').astype(float))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "puts = pd.DataFrame(puts.rename(\n",
    "        columns={'Daily settlem. price': 'Put_Price'}\n",
    "                            ).pop('Put_Price').astype(float))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These two get then merged via the function ``merge_and_filter()`` into another new ``DataFrame`` object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "dataset = icod.merge_and_filter(puts, calls)\n",
    "dataset.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This whole procedure is implemented in the function ``collect_option_series()`` which yields the same result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "os = icod.collect_option_series(12, 2020, target_day)\n",
    "os.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function ``data_collection()`` repeats this procedure for all those dates for which option data is available and writes (appends) the results in a HDF5 database file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# uncomment to initiate the process (takes a while)\n",
    "# %time icod.data_collection(path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the further analyses, we open this HDF5 database file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "store = pd.HDFStore(path + 'index_option_series.h5', 'r')\n",
    "store"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The collected option series data is easily read from the HDF5 database file in monthly chunks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "Dec20 = store['Dec20']\n",
    "Dec20.info()\n",
    "store.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some selected option prices from the large data set:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "Dec20.iloc[25:35]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calculating the Sub-Indexes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this section, we use the data file created in the previous one. For all dates of the data file, the Python module ``index_subindex_calculation.py`` (see the appendix for the complete script) used in this section decides whether the VSTOXX 1M sub-index is defined or not (remember that the sub-index is not defined at the final settlement day and one day before). If it is defined, the script computes the value of the sub-indexes VSTOXX 1M and VSTOXX 2M; if not, it computes the values of the sub-indexes VSTOXX 2M and VSTOXX 3M, respectively. Finally, it returns a pandas ``DataFrame`` object with the three time series."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The Algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we focus on the computation of the value of a single sub-index for a given date. Given are the prices $C_i, i \\in \\{0,...,n\\},$ of a series of  European call options on the EURO STOXX 50 with fixed maturity date $T$ and exercise prices $K_i, i \\in \\{0,...,n\\},$ as well as the prices $P_i, i \\in \\{0,...,n\\},$ of a series of European put options on EURO STOXX 50 with the same maturity date $T$ and exercise prices $K_i$. Let further hold $K_i < K_{i+1}$ for all $i \\in \\{0,....,n-1\\}$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, the value of the relevant sub-index $V$ is as follows (see also the chapter about _Model-Free Replication of Variance_):"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "V = 100 \\cdot \\sqrt{\\hat{\\sigma}^2}\n",
    "$$\n",
    "\n",
    "with\n",
    "\n",
    "$$\n",
    "\\hat{\\sigma}^2 = \\frac{2}{T} \\sum_{i=0}^n \\frac{\\Delta K_i}{{K_i}^2} \\mathrm{e}^{rT} M_i - \\frac{1}{T}\\left( \\frac{F}{K_*}-1\\right)^2\n",
    "$$\n",
    "\n",
    "where\n",
    "\n",
    "$$\n",
    "\\begin{array}{ll}\n",
    " \\Delta K_i &=\\left\\{ \\begin{array}{ll} K_1-K_0 & \\mbox{for } i=0 \\\\  \\dfrac{K_{i+1}-K_{i-1}}{2} &  \\mbox{for } i = 1,...,n-1 \\\\   K_n-K_{n-1} & \\mbox{for } i=n \\end{array} \\right. \\\\  \\\\\n",
    " r          &=  \\mbox{constant risk-free short rate appropriate for maturity $T$} \\\\ \\\\\n",
    " F \t    &= K_j+ \\mathrm{e}^{rT}|C_j-P_j|, \\mbox{ where } j=\\displaystyle \\min_{i \\in \\{0,...,n\\}}\\{|C_i-P_i|\\} \\\\ \\\\\n",
    " K_*        &= \\displaystyle \\max_{ K_{i | i \\in \\{0,...,n\\}}} \\{K_i < F \\}, \\\\ \\\\\n",
    " M_i        & =    \\left\\{ \\begin{array}{ll} P_i & \\mbox{for } K_i<K_* \\\\  \\dfrac{P_i-C_i}{2} &  \\mbox{for } K_i=K_*\\\\   C_i & \\mbox{for } K_i>K_* \\end{array} \\right.\n",
    "\\end{array}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We implement a function to compute one value of a single sub-index. Thereafter, we extend that function to compute time series for both VSTOXX 1M and VSTOXX 2M indexes as well as parts of the VSTOXX 3M index. Imports again make up the beginning of the script."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!sed -n 10,15p scripts/index_subindex_calculation.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A core function of the script is ``compute_subindex()``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import index_subindex_calculation as isc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "isc.compute_subindex??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This script calculates a single index value. It implements mainly the following steps:\n",
    "\n",
    "* the calculation of $\\Delta K_i$\n",
    "* the computation of the forward price and the index of $K_*$\n",
    "* the selection of the at-the-money option and the out-of-the-money options\n",
    "* the combination of the results of the other three steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The next step is the derivation of time series data for the VSTOXX 1M and VSTOXX 2M as well as parts of VSTOXX 3M indexes and storage of the results in a pandas ``DataFrame`` object. As data source we use the file created in the last section. Remember, that this file contains a dictionary-like ``HDFStore`` object with one entry for every options series. The keys for the entries are three letter abbreviations of the respective month's name plus the actual year represented by two numbers, for example ``Mar16``, ``Jun16``, ``Dec20`` and so on. The value of an entry is a pandas ``DataFrame`` object with a pandas ``MultiIndex`` (date, strike price) and prices for the put and call options for the dates and strike prices."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All this is implemented as function ``make_subindex()``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "isc.make_subindex??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function uses the collected option series data and selects those data sub-sets needed for the calculation at hand. It generates sub-index values for all those days for which option data is available. The result is a pandas ``DataFrame`` object.\n",
    "\n",
    "Let us see how it works. To this end, we first import the module as ``isc``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import index_subindex_calculation as isc\n",
    "si = isc.make_subindex(path)\n",
    "si"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For comparison, we retrieve the \"real\" historical VSTOXX (sub-) index values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'https://hilpisch.com/vstoxx_eikon_eod_data.csv'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vs = pd.read_csv(url, index_col=0, parse_dates=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vs.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, combine the re-calculated VSTOXX 2M values with the historical ones into a new ``DataFrame`` object and add a new column with the absolute differences."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "comp = pd.concat((si['V6I2'], vs['.V6I2']),\n",
    "          axis=1, join='inner')\n",
    "comp.index = comp.index.normalize()\n",
    "comp.columns = ['CALC', 'REAL']\n",
    "comp['DIFF'] = comp['CALC'] - comp['REAL']\n",
    "comp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following figure shows the two time series in direct comparison."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "from pylab import mpl, plt\n",
    "plt.style.use('seaborn')\n",
    "mpl.rcParams['font.family'] = 'serif'  # set serif font"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "comp[['CALC', 'REAL']].plot(style=['ro', 'b'], figsize=(10, 6));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"font-family: monospace;\">Calculated VSTOXX 2M sub-index values vs. real ones."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following figure shows the point-wise differences between the two time series."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.bar(comp.index, comp['DIFF'])\n",
    "plt.gcf().autofmt_xdate();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"font-family: monospace;\">Differences of calculated VSTOXX 2M index values and real ones."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calculating the VSTOXX Index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the values for the sub-indexes VSTOXX 1M and VSTOXX 2M, $V_1$ and $V_2$ say, are given, then the value for the VSTOXX index itself, $V$ say, is calculated by the linear interpolation of $V_1$ and $V_2$:\n",
    "\n",
    "$$\n",
    "V = \\sqrt{\\left(T_1\\cdot V_1^2\\cdot\\left(\\frac{N_{T_{2}}-N_{30}}{N_{T_{2}}-N_{T_1}}\\right)+T_{2}\\cdot V_2^2\\cdot\\left(\\frac{N_{30}-N_{T_1}}{N_{T_{2}}-N_{T_{1}}}\\right)\\right)\\cdot\\frac{N_{365}}{N_{30}}}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where\n",
    "\n",
    "* $N_{T_1}=$ time to expiry of $V_1$´s options series in seconds\n",
    "* $N_{T_2}=$ time to expiry of $V_2$´s options series in seconds\n",
    "* $N_{30}= 30$ days in seconds\n",
    "* $N_{365}=$ time for a standard year in seconds\n",
    "* $T_1= N_{T_1}/N_{365}$\n",
    "* $T_2= N_{T_2}/N_{365}$\n",
    "\n",
    "Recall that the sub-index VSTOXX 1M is not defined on the final settlement day of the underlying option series and the day before. For these dates, we use VSTOXX 2M and VSTOXX 3M as $V_1$ and $V_2$, respectively."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python module ``index_vstoxx_calculation.py`` (see the appendix for the module in its entirety) implements the VSTOXX index calculation routine &mdash; given the respective sub-index time series data sets. The module starts like usual with some imports."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!sed -n 9,12p scripts/index_vstoxx_calculation.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function ``calculate_vstoxx()`` is the core of the module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import index_vstoxx_calculation as ivc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ivc.calculate_vstoxx??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As its single argument, the function takes the path to a CSV file containing historical VSTOXX data for the index itself and the sub-indexes. The re-calculation of it then is as straightforward as follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "import index_vstoxx_calculation as ivc\n",
    "%time data = ivc.calculate_vstoxx(url)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us inspect the pandas ``DataFrame`` with the results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A brief look at the absolute average error of the re-calculation reveals that the implementation yields quite accurate results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## output: average error of re-calculation\n",
    "data['Difference'].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following figure compares the original `.V2TX` time series with the re-calculated values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## original vs. re-calculated VSTOXX index\n",
    "data[['.V2TX', 'VSTOXX']].plot(subplots=True, figsize=(10, 6),\n",
    "                              style=\"blue\", grid=True);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## original vs. re-calculated VSTOXX index\n",
    "data[['.V2TX', 'VSTOXX']].plot(figsize=(10, 6), style=['-', '.']);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"font-family: monospace;\">Historical VSTOXX index values re-calculated vs. real ones."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, the following figure presents the absolute differences. The figure shows that the differences are in general marginal with a few outliers observed here and there."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "## differences between single values\n",
    "data['Difference'].plot(figsize=(10, 6), style=\"r\", grid=True,\n",
    "                        ylim=(-1, 1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"font-family: monospace;\">Differences of historical VSTOXX index values re-calculated vs. real ones."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This chapter (re-) calculates the  VSTOXX volatility index based on historical sub-index values and based on the volatility index definition as derived in the chapter _Model-Free Replication of Variance_. The chapter also shows how to calculate the sub-index values themselves based on EURO STOXX 50 options data. Python code is provided to automatically collect such data from the Eurex web site."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python Scripts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ``index_collect_option_data.py``"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cat scripts/index_collect_option_data.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `index_subindex_calculation.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cat scripts/index_subindex_calculation.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `index_vstoxx_calculation.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cat scripts/index_vstoxx_calculation.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://hilpisch.com/tpq_logo.png\" alt=\"The Python Quants\" width=\"35%\" align=\"right\" border=\"0\"><br>\n",
    "\n",
    "<a href=\"http://tpq.io\" target=\"_blank\">http://tpq.io</a> | <a href=\"http://twitter.com/dyjh\" target=\"_blank\">@dyjh</a> | <a href=\"mailto:team@tpq.io\">team@tpq.io</a>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
